/*  ----------------------------------------------------------------------------
 *  Arello Mobile
 *  Fast 3d Engine
 *  ----------------------------------------------------------------------------
 * Except where otherwise noted, this work is licensed under
 * http://creativecommons.org/licenses/by/3.0
 */

#include "Camera.h"
#include "Root.h"
#include <xml/Stream.h>
#include <safe_new.h>
#include <Converter.h>
#include <string>
#include <lib3d/hard/Hardware.h>
#include <lib3d/math.h>
#include <logs/Log.h>

///#define SPEED_TEST

namespace liba
{
namespace lib3d
{
namespace node
{

const Atom Camera::near_plane_name( "NearPlane" );
const Atom Camera::far_plane_name( "FarPlane" );
const Atom Camera::fog_color_name( "FogColor" );
const Atom Camera::fog_range_name( "FogRange" );

Camera::Camera(const Atom & name, Node * parent )
:	Node( name, parent )
{
	get_root()->add_camera( this );
}

Camera::~Camera()
{
	get_root()->remove_camera( this );
}

bool Camera::get_attribute( const Atom & name, double * value )const
{
	if( name == near_plane_name )
	{
		*value = desc.near_plane;
		return true;
	}
	if( name == far_plane_name )
	{
		*value = desc.far_plane;
		return true;
	}
	if( name == fog_range_name )
	{
		*value = desc.fog_range;
		return true;
	}
	return Node::get_attribute( name, value );
}


bool Camera::change_attribute( const Atom & name, double value )
{
	if( name == near_plane_name )
	{
		desc.near_plane = value;
		on_change_parameters();
		return true;
	}
	if( name == far_plane_name )
	{
		desc.far_plane = value;
		on_change_parameters();
		return true;
	}
	if( name == fog_range_name )
	{
		desc.fog_range = value;
		on_change_parameters();
		return true;
	}
	return Node::change_attribute( name, value );
}

bool Camera::on_attribute( xml::Provider * prov, const std::string & name, const std::string & value )
{
	if ( name == "NearPlane" )
	{
		return converter::convert( value, &desc.near_plane );
	}
	if ( name == "FarPlane" )
	{
		return converter::convert( value, &desc.far_plane );
	}
	if ( name == "FogRange" )
	{
		return converter::convert( value, &desc.fog_range );
	}
	if ( name == "FogColor" )
	{
		return converter::convert( value, &desc.fog_color );
	}
	if ( name == "ViewportLeft" )
	{
		return converter::convert( value, &desc.viewport.left );
	}
	if ( name == "ViewportRight" )
	{
		return converter::convert( value, &desc.viewport.right );
	}
	if ( name == "ViewportTop" )
	{
		return converter::convert( value, &desc.viewport.top );
	}
	if ( name == "ViewportBottom" )
	{
		return converter::convert( value, &desc.viewport.bottom );
	}
	return Node::on_attribute( prov, name, value );
}

bool Camera::on_end_node( xml::Provider * prov )
{
	on_change_parameters();
	return true;
}

const CameraDesc & Camera::get_desc()
{
	desc.world = get_full_matrix();
	return desc;
}

bool Camera::start_render_to_list( hard::Hardware * hardware, hard::RenderList * render_list )
{
#ifdef SPEED_TEST
	__int64 now = threads::get_precise_tick_count();
#endif
	CameraDesc desc = get_desc();
	render_list->camera_world = desc.world;
	render_list->camera_projection = desc.projection;
	render_list->viewport = desc.viewport;
	render_list->fog_color = desc.fog_color;
	render_list->fog_range = desc.fog_range;
	get_root()->render_to_list( hardware, render_list );
#ifdef SPEED_TEST
	int passed = threads::get_precise_tick_count() - now;
	logs::log() << "\t\tCamera::start_render_to_list(" << get_name().get_str() << "):" << passed * threads::get_precise_tick_time()*1000 << " msec\n";
#endif
	return true;
}

} // namespace node
} // namespace lib3d
} // namespace liba

